
package com.example.tys.baseapplication.net_tcp.frame.future;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author tys
 */
public abstract class AbstractCompletionFuture<T> implements java.util.concurrent.Future<T> {

    volatile T mResult = null;
    volatile String uniqueId;

    AbstractCompletionFuture(String uniqueId) {
        this.uniqueId = uniqueId;
    }

    @Override
    public boolean isDone() {
        return mResult != null;
    }

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
    }

    @Override
    public boolean isCancelled() {
        return false;
    }

    @Override
    public T get() throws InterruptedException {
        try {
            return get(-1, TimeUnit.SECONDS);
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        return mResult;
    }

    @Override
    public T get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
        while (!isDone()) {
            if (timeout > 0) {
                await(timeout, unit);
            } else {
                await();
            }
            if (timeout > 0) {
                if (!isDone()) {
                    throw new TimeoutException();
                }
                break;
            }
        }
        return mResult;
    }

    public void setResult(T mResult) {
        this.mResult = mResult;
        signal();
    }

    /**
     * Wakes up one waiting thread.
     *
     * @see java.util.concurrent.Future#get()
     * @see java.util.concurrent.Future#get(long, TimeUnit)
     */
    public abstract void signal();

    /**
     * Causes the current thread to wait until it is signalled or
     * {@linkplain Thread#interrupt interrupted}.
     *
     * @throws InterruptedException if the current thread was interrupted while waiting
     */
    abstract void await() throws InterruptedException;

    /**
     * Causes the current thread to wait until it is signalled or interrupted,
     * or the specified waiting time elapses.
     *
     * @param time the maximum time to wait
     * @param unit the time unit of the {@code time} argument
     * @throws InterruptedException if the current thread was interrupted while waiting
     * @throws TimeoutException     if the wait timed out
     */
    abstract void await(long time, TimeUnit unit) throws InterruptedException, TimeoutException;
}